use crate::error::*;
use std::sync::Arc;

use openssl::{
    pkey::{PKey, Private},
    x509::{X509Ref, X509},
};
use serde::{Deserialize, Serialize};

#[allow(dead_code)]
pub struct SslProtoVersion(usize);

#[allow(dead_code)]
impl SslProtoVersion {
    pub const SSL3: usize = 0x0004;
    pub const TLS1: usize = 0x0008;
    pub const TLS1_1: usize = 0x0010;
    pub const TLS1_2: usize = 0x0020;
    pub const TLS1_3: usize = 0x0040;

    pub const SSL3_STR: &str = "SSLv3";
    pub const TLS1_STR: &str = "TLSv1";
    pub const TLS1_1_STR: &str = "TLSv1.1";
    pub const TLS_1_2_STR: &str = "TLSv1.2";
    pub const TLS1_3_STR: &str = "TLSv1.3";
}

#[allow(unused)]
pub const FFDHE_2048: &str = "
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----
";

pub static DEFAULT_GROUP_LIST: &str = "X25519:P-256:P-384";

pub static DEFAULT_CIPHER_LIST: &str =
    "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
     ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
     DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305";

pub static DEFAULT_CIPHERSUITES: &str =
    "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_SM4_GCM_SM3";

pub static DEFAULT_TLS_NTLS_CIPHER_LIST: &str =
    "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
       ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
       DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:\
       ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3:ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:\
       RSA-SM4-CBC-SM3:RSA-SM4-GCM-SM3:RSA-SM4-CBC-SHA256:RSA-SM4-GCM-SHA256";

#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SslAcceptorConf {
    // 是否开启NTLS, 默认false.
    pub enable_ntls: Option<bool>,

    // TLS协议版本, 默认None.
    pub proto_version: Option<Vec<String>>,

    pub groups_list: Option<String>,
    pub cipher_list: Option<String>,
    pub ciphersuites: Option<String>,

    // 该文件必须同时包含证书链、证书和私钥.
    pub cert_path: Option<String>,

    // for test
    leaf_cert: Option<Vec<u8>>,
    pkey: Option<Vec<u8>>,
    chain_certs: Vec<Vec<u8>>,
}

#[allow(dead_code)]
impl SslAcceptorConf {
    pub fn set_leaf_cet(&mut self, cert: X509) {
        self.leaf_cert = Some(cert.to_der().unwrap());
    }

    pub fn set_pkey(&mut self, pkey: PKey<Private>) {
        self.pkey = Some(pkey.private_key_to_der().unwrap());
    }

    pub fn set_chain_certs(&mut self, chain_certs: Vec<X509>) {
        self.chain_certs.clear();
        for v in &chain_certs {
            self.chain_certs.push(v.to_der().unwrap());
        }
    }

    pub fn to_runtime_conf(
        &self,
        pre_conf: Option<&Arc<SslAcceptorRuntimeConf>>,
    ) -> Result<Arc<SslAcceptorRuntimeConf>> {
        let def_enable_ntls;
        let def_proto_version;
        let def_groups_list;
        let def_cipher_list;
        let def_ciphersuites;
        let def_cert_path;

        match pre_conf {
            Some(pre_conf) => {
                def_enable_ntls = pre_conf.enable_ntls;
                def_proto_version = pre_conf.proto_version;
                def_groups_list = pre_conf.groups_list.clone();
                def_cipher_list = pre_conf.cipher_list.clone();
                def_ciphersuites = pre_conf.ciphersuites.clone();
                def_cert_path = pre_conf.cert_path.clone();
            }

            None => {
                def_enable_ntls = false;
                def_proto_version = None;
                def_groups_list = "".to_string();
                def_cipher_list = "".to_string();
                def_ciphersuites = "".to_string();
                def_cert_path = "".to_string();
            }
        }

        let enable_ntls = self.enable_ntls.unwrap_or(def_enable_ntls);
        let proto_version = match &self.proto_version {
            Some(proto) => {
                let mut proto_version = 0;
                for v in proto {
                    if v == SslProtoVersion::SSL3_STR {
                        proto_version |= SslProtoVersion::SSL3;
                    }
                    if v == SslProtoVersion::TLS1_STR {
                        proto_version |= SslProtoVersion::TLS1;
                    }
                    if v == SslProtoVersion::TLS1_1_STR {
                        proto_version |= SslProtoVersion::TLS1_1;
                    }
                    if v == SslProtoVersion::TLS_1_2_STR {
                        proto_version |= SslProtoVersion::TLS1_2;
                    }
                }
                Some(proto_version)
            }
            None => def_proto_version,
        };

        let groups_list = self.groups_list.clone().unwrap_or(def_groups_list);
        let cipher_list = self.cipher_list.clone().unwrap_or(def_cipher_list);
        let ciphersuites =
            self.ciphersuites.clone().unwrap_or(def_ciphersuites);
        let cert_path = self.cert_path.clone().unwrap_or(def_cert_path);

        // TODO: 读取cert-path, 解析文件, 并设置如下三个变量.
        let mut leaf_cert: Option<X509> = None;
        let mut pkey = None;
        let mut chain_certs = Vec::new();

        // TODO: 在实际使用中, 我们通过读取cert_path进行解析, 并设置上述三个变量.
        // TODO: 暂未实现.
        if !cert_path.is_empty() {
            // TODO: parse & set leaf_cert/pkey/chain_certs.
        }

        // for test
        if self.leaf_cert.is_some() {
            leaf_cert =
                Some(X509::from_der(self.leaf_cert.as_ref().unwrap()).unwrap());
        }

        // for test
        if self.pkey.is_some() {
            pkey = Some(
                PKey::private_key_from_der(self.pkey.as_ref().unwrap())
                    .unwrap(),
            );
        }

        // for test
        for v in &self.chain_certs {
            chain_certs.push(v.clone());
        }

        let runtime_conf = SslAcceptorRuntimeConf {
            enable_ntls,
            proto_version,
            groups_list,
            cipher_list,
            ciphersuites,
            leaf_cert,
            pkey,
            chain_certs,
            cert_path,
        };

        Ok(Arc::new(runtime_conf.valid()?))
    }
}

#[allow(dead_code)]
pub struct SslAcceptorRuntimeConf {
    pub enable_ntls: bool,
    pub proto_version: Option<usize>,
    pub groups_list: String,
    pub cipher_list: String,
    pub ciphersuites: String,
    pub leaf_cert: Option<X509>,
    pub pkey: Option<PKey<Private>>,
    // 受Rust所有权影响, 此处需先将X509转换为der格式.
    // 在使用过程中重新生成X509对象.
    // 请使用 set_chain_certs 设置 chain_certs.
    chain_certs: Vec<Vec<u8>>,

    cert_path: String,
}

#[allow(dead_code)]
impl SslAcceptorRuntimeConf {
    pub fn valid(mut self) -> Result<Self> {
        if self.groups_list.is_empty() {
            self.groups_list = DEFAULT_GROUP_LIST.to_string();
        }

        if self.cipher_list.is_empty() {
            if self.enable_ntls {
                self.cipher_list = DEFAULT_TLS_NTLS_CIPHER_LIST.to_string();
            } else {
                self.cipher_list = DEFAULT_CIPHER_LIST.to_string();
            }
        }

        if self.ciphersuites.is_empty() {
            self.ciphersuites = DEFAULT_CIPHERSUITES.to_owned();
        }

        Ok(self)
    }

    pub fn get_leaf_cert(&self) -> Option<&X509Ref> {
        match &self.leaf_cert {
            Some(cert) => Some(cert.as_ref()),

            None => None,
        }
    }

    pub fn set_chain_certs(&mut self, chain_certs: Vec<X509>) {
        self.chain_certs.clear();

        for v in &chain_certs {
            let der = v.to_der().unwrap();
            self.chain_certs.push(der);
        }
    }

    pub fn set_chain_certs_unchecked(&mut self, chain_certs: Vec<Vec<u8>>) {
        self.chain_certs.clear();
        for v in &chain_certs {
            self.chain_certs.push(v.clone());
        }
    }

    pub fn get_chain_certs(&self) -> &Vec<Vec<u8>> {
        &self.chain_certs
    }
}
